package com.zxd.interview.zkcurator;


import lombok.extern.slf4j.Slf4j;
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.api.CuratorEventType;
import org.apache.curator.framework.recipes.cache.NodeCache;
import org.apache.curator.framework.recipes.cache.NodeCacheListener;
import org.apache.curator.framework.state.ConnectionStateListener;
import org.apache.curator.retry.ExponentialBackoffRetry;

/**
 * CuratorTestExample
 *
 */
@Slf4j
public class CuratorTestExample {

    public static void main(String[] args) throws Exception {
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
        CuratorFramework client =
                CuratorFrameworkFactory.newClient("192.168.19.100:2181,192.168.19.101:2181,192.168.19.102:2181", retryPolicy);
//        CuratorFramework client =
//                CuratorFrameworkFactory.newClient("192.168.154.128:2181,192.168.154.130:2181,192.168.154.131:2181", retryPolicy);

        // 连接ZK,开启连接

        // 自定义监听器 CuratorListener
        client.getCuratorListenable().addListener((_fk, e) -> {
            if (e.getType().equals(CuratorEventType.WATCHED)) {
                log.info("测试");
            }

        });
        ConnectionStateListener connectionStateListener = (client1, newState) -> {
            //Some details
            log.info("newState => "+ newState);
        };
        // 11:31:17.026 [Curator-ConnectionStateManager-0] INFO com.zxd.interview.zkcurator.CuratorTestExample - newState => CONNECTED
        client.getConnectionStateListenable().addListener(connectionStateListener);


        client.start();
        // 需要先启动client再启动NodeCache监听
        // Expected state [STARTED] was [LATENT]

        //----------------- 监听单 个节点 -----------------------------------
        //1. 创建NodeCache对象
        final NodeCache nodeCache = new NodeCache(client,"/testNodeCache");
        NodeCacheListener listener = () -> log.info("节点变化了~");
        //2. 注册监听
        nodeCache.getListenable().addListener(() -> {
            log.info("节点变化了~");
            //获取修改节点后的数据
            byte[] data = nodeCache.getCurrentData().getData();
            log.info(new String(data));
        });
        nodeCache.getListenable().addListener(listener);

        // 3. 开启监听.如果设置为true，则开启监听，加载缓冲数据
        nodeCache.start(true);

        // 4. 设置节点
        // 如果主节点是临时的话，就不能构建其子节点
//        client.create().creatingParentsIfNeeded().withMode(CreateMode.CONTAINER).forPath("/testNodeCache");
        client.create().creatingParentsIfNeeded().forPath("/testNodeCache/bcc", "Test".getBytes());
        client.create().creatingParentsIfNeeded().forPath("/testNodeCache/aaaa", "Test".getBytes());
        client.create().creatingParentsIfNeeded().forPath("/testNodeCache/bbbb", "Test".getBytes());
        // 5. 修改节点，查看是否监听到节点变化
//        client.setData().forPath("/testNodeCache","helloWorld".getBytes());
        // 6. 删除节点
        client.delete().deletingChildrenIfNeeded().forPath("/testNodeCache");


        // 此处就获取到 zk的一个连接实例。
        //.....
        // 创建znode，如果有必要需要创建父目录

        // 创建一个节点，初始内容为空
//        client.create().forPath("/tmp");
        // 创建一个节点，附带初始内容
//        client.create().forPath("/tmp", "init".getBytes());;

        // 创建一个临时节点，初始内容为空
//        client.create().withMode(CreateMode.EPHEMERAL).forPath("/temp");

        // 试图对一个不存在的父节点创建子节点
//        client.create().withMode(CreateMode.EPHEMERAL).forPath("/temp/childNode");
//        client.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL).forPath("/temp/childNode", "init".getBytes());
        // 报错KeeperErrorCode = NoNode for /temp/childNode
//        client.close();


//        client.create().creatingParentsIfNeeded().withMode(CreateMode.CONTAINER).forPath("/my/path", "Test".getBytes());
//        client.create().orSetData().forPath("/my/path", "Test".getBytes());
//        client.getData().forPath("/my/path");
//        Stat stat = client.checkExists().forPath("/my/path");
//
//        client.delete().deletingChildrenIfNeeded().forPath("/my/path");
//        client.close();

        // 先创建一个持久节点
//        client.create().forPath("/create");
        // 删除节点
//        client.delete().forPath("/create");
        // 如果节点不存在：KeeperErrorCode = NoNode for /create


        // 先创建一个持久节点
//        client.create().creatingParentsIfNeeded().forPath("/create/child0");
//        client.create().creatingParentsIfNeeded().forPath("/create/child1");
        // 删除并且判断是否需要同时删除子节点，如果有子节点并且确定一并删除需要添加 deletingChildrenIfNeeded
//        client.delete().deletingChildrenIfNeeded().forPath("/create");
//        必须成功地删除，删除不成功会持续重试
//        client.delete().guaranteed().forPath("/app1");



//        client.create().creatingParentsIfNeeded().withMode(CreateMode.CONTAINER).forPath("/app2", "Test".getBytes());
        //1、查询数据：get
//        byte[] data = client.getData().forPath("/app2");
        // KeeperErrorCode = NoNode for /app1
//        log.info("查询数据 {}", new String(data));
        // 运行结果：查询数据 Test

        //2、查询子节点：ls
//        List<String> list = client.getChildren().forPath("/app2");
//        log.info("查询子节点 {}", list);
        //运行结果：查询子节点 []

        //1、修改节点数据（基本修改）
//        client.create().creatingParentsIfNeeded().withMode(CreateMode.CONTAINER).forPath("/app2", "Test".getBytes());
//        client.setData().forPath("/app2", "333".getBytes(StandardCharsets.UTF_8));

//2、根据版本号修改
//        Stat stat1 = new Stat();
//        client.getData().storingStatIn(stat1).forPath("/app1");
//        client.setData().withVersion(stat1.getVersion()).forPath("/app1", "itcast".getBytes(StandardCharsets.UTF_8));

        client.close();
        //3、查询节点状态信息：ls -s
//        Stat stat = new Stat();
//        client.getData().storingStatIn(stat).forPath("/app2");

//        System.out.println(stat);

//        InterProcessMutex lock = new InterProcessMutex(client, "/my/path");
//        lock.acquire();
//        try {
//            // do some work inside of the critical section here
//            Thread.sleep(1000);
//        } finally {
//            lock.release();
//        }
//
    }
}
